package com.github.paicoding.forum.web.hook.interceptor;

import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.github.paicoding.forum.api.model.context.ReqInfoContext;
import com.github.paicoding.forum.api.model.vo.ResVo;
import com.github.paicoding.forum.api.model.vo.constants.StatusEnum;
import com.github.paicoding.forum.core.permission.Permission;
import com.github.paicoding.forum.core.permission.UserRole;
import com.github.paicoding.forum.core.util.JsonUtil;
import com.github.paicoding.forum.core.util.SpringUtil;
import com.github.paicoding.forum.service.rank.service.UserActivityRankService;
import com.github.paicoding.forum.service.rank.service.model.ActivityScoreBo;
import com.github.paicoding.forum.web.global.GlobalInitService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.AsyncHandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 注入全局的配置信息：
 * - thymleaf 站点信息，基本信息，在这里注入
 *
 */
@Slf4j
@Component
public class GlobalViewInterceptor implements AsyncHandlerInterceptor {
    @Autowired
    private GlobalInitService globalInitService;

    // 请求处理前的逻辑
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 仅处理控制器方法（HandlerMethod），忽略静态资源等其他请求
        if (handler instanceof HandlerMethod) {
            HandlerMethod handlerMethod = (HandlerMethod) handler;
            // 获取权限注解（先方法，后类，方法注解优先级更高）
            Permission permission = handlerMethod.getMethod().getAnnotation(Permission.class);
            
            if (permission == null) {
                permission = handlerMethod.getBeanType().getAnnotation(Permission.class);
            }

            // 情况1：无权限注解 或 权限为“所有人可访问（UserRole.ALL）”
            if (permission == null || permission.role() == UserRole.ALL) {
                // 若有请求上下文（已登录用户），更新活跃度（访问路径加分）
                if (ReqInfoContext.getReqInfo() != null) {
                    SpringUtil.getBean(UserActivityRankService.class).addActivityScore(ReqInfoContext.getReqInfo().getUserId(), new ActivityScoreBo().setPath(ReqInfoContext.getReqInfo().getPath()));
                }
                return true;
            }

            // 情况2：有权限注解，但用户未登录（无请求上下文或用户ID）
            if (ReqInfoContext.getReqInfo() == null || ReqInfoContext.getReqInfo().getUserId() == null) {
                // 若为Rest接口（@ResponseBody或@RestController），返回JSON格式未登录错误
                if (handlerMethod.getMethod().getAnnotation(ResponseBody.class) != null
                        || handlerMethod.getMethod().getDeclaringClass().getAnnotation(RestController.class) != null) {
                    // 访问需要登录的rest接口
                    response.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE);
                    response.getWriter().println(JsonUtil.toStr(ResVo.fail(StatusEnum.FORBID_NOTLOGIN)));
                    response.getWriter().flush();
                    return false;
                    // 若为管理员路径，重定向到管理员登录页
                } else if (request.getRequestURI().startsWith("/api/admin/") || request.getRequestURI().startsWith("/admin/")) {
                    response.sendRedirect("/admin");
                    // 其他页面，重定向到首页（登录页通常在首页）
                } else {
                    response.sendRedirect("/");
                }
                return false;
            }

            // 情况3：用户已登录，但权限不足（需管理员角色，当前非管理员）
            if (permission.role() == UserRole.ADMIN && !UserRole.ADMIN.name().equalsIgnoreCase(ReqInfoContext.getReqInfo().getUser().getRole())) {
                // 设置为无权限
                response.setStatus(HttpStatus.FORBIDDEN.value());
                return false;
            }
        }
        return true;
    }

    // postHandle 在 Controller 方法执行完毕、视图渲染前执行，核心作用是给视图（ModelAndView）注入全局属性
    // 供前端模板（如 Thymeleaf）使用。
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // 仅处理有视图的请求（ModelAndView非空）
        if (!ObjectUtils.isEmpty(modelAndView)) {
            // 处理异常页面（响应状态非200 OK）
            if (response.getStatus() != HttpStatus.OK.value()) {
                try {
                    // 重新初始化请求上下文（避免异常时登录信息丢失）
                    ReqInfoContext.ReqInfo reqInfo = new ReqInfoContext.ReqInfo();
                    // fixme 对于异常重定向到 /error 时，会导致登录信息丢失，待解决
                    // 初始化登录用户信息
                    globalInitService.initLoginUser(reqInfo);
                    // 存入上下文
                    ReqInfoContext.addReqInfo(reqInfo);
                    // 注入全局属性
                    modelAndView.getModel().put("global", globalInitService.globalAttr());
                } finally {
                    ReqInfoContext.clear();
                }
            } else {
                // 正常页面，直接注入全局属性
                modelAndView.getModel().put("global", globalInitService.globalAttr());
            }
        }

    }
}
